/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.azon.left.hand;

import com.isip.chaincode.ChainCode;
import java.awt.Point;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/**
 *
 * @author Mahdan Ahmad F A
 */
public class WetLeftHand{
    public int[][] blackAndWhiteConverter(int[][] matrix) {
        int[][] new_matrix = new int[matrix.length][matrix[0].length];
        
        
        for (int m = 0; m < matrix.length; m++) {
            for (int n = 0; n < matrix[0].length; n++) {
                if (matrix[m][n] > 120) {
                    new_matrix[m][n] = 1;
                } else {
                    new_matrix[m][n] = 0;
                }
            }
        }
        
        return new_matrix;
    }
    
    public String[] doWetLeftHand(int[][] matrix) {
        ArrayList<String> array = new ArrayList<>();
        
        int[] start = detectorBlack(matrix);
        
        int iteration = 0;
        
        while (((start[0] != -28) && (start[1] != -28)) /*&& (iteration < 3)*/) {
            array.add(createAChainCode(matrix, start[0], start[1]));
            
            //flood_matrix = matrix;
            
            matrix = floodFill(matrix, start[0], start[1], 1);
            
            //matrix = flood_matrix;
            start   = detectorBlack(matrix);
            
            iteration++;
        } // 
        
        String[] chain_codes = array.toArray(new String[array.size()]);
        ChainCode chaincode = new ChainCode(0, 0, getChainCode(chain_codes[0]));
        System.out.println("Chaincode " + chaincode.getChaincode());
        System.out.println("Cleaned Chaincode " +chaincode.cleanChainCode());
        System.out.println("Sequence Chaincode " +chaincode.getSequence());
        System.out.println("Advance Sequence Chaincode " +chaincode.getAdvanceSequence());
        return chain_codes;
    }
    
    public String guessObject(String chain_code) {
        String shape = "";
        
        String  code        = getChainCode(chain_code);
        int[]   frequency   = getFrequency(chain_code);
        String  sequence    = new ChainCode(0,0,code).getAdvanceSequence();
        
        /*
        System.out.println("Frekuensi");
        for (int i = 0; i < frequency.length; i++) {
            System.out.println((i + 1) + " = " + frequency[i]);
        }
        System.out.println("");
        System.out.println("Sequence = " + sequence);
        System.out.println(""); // */
        if (maybeSquere(code, sequence, frequency)) {
            shape = "persegi";
        } else if (maybeTriangle(code, sequence, frequency)) {
            shape = "segitiga";
        } else if (maybeDiamond(code, sequence, frequency)) {
            shape = "wajik";
        } else if (maybeCircle(code, sequence, frequency)) {
            shape = "lingkaran";
        } else if (maybeHexagon(code, sequence, frequency)) {
            shape = "segi enam";
        } else {
            shape = "tidak dikenali";
        }
        
        return shape;
    }
    
    private int[] detectorBlack(int[][] matrix) {
        
        int[] start = new int[2];
        
        start[0] = -28;
        start[1] = -28;
        
        for (int m = 0; m < matrix.length; m++) {
            for (int n = 0; n < matrix[0].length; n++) {
                
                if (matrix[m][n] == 0 ) {
                    start[0] = m;
                    start[1] = n;
                    
                    return start;
                }
            }
        }
        
        return start;
        
    }
       
    private String createAChainCode(int[][] matrix, int startX, int startY) {
        
        String chain_code = "";
        
        String north        = "12369874";
        String northEast    = "23698741";
        String east         = "36987412";
        String southEast    = "69874123";
        String south        = "98741236";
        String southWest    = "87412369";
        String west         = "74123698";
        String northWest    = "41236987";
        
        String precedence = southEast;
        
        int direction;
        
        int nextX = -99;
        int nextY = -99;
        
        int iteration = 0;
        
        System.out.println("Start " + startX +","+startY);
        while ((!(startX == nextX) || !(startY == nextY))/* && (iteration < 100)*/) {
            if (chain_code.isEmpty()) {
                direction = 0;
                nextX = startX;
                nextY = startY;   
            } else {
                direction = chain_code.charAt(chain_code.length() - 1) - 48;
            }
            
            System.out.println("************************************************");
            System.out.println("Iterasi ke-" + (iteration + 1) + " = " + nextX + " " + nextY);
            
            switch(direction) {
                case 1:
                    precedence = northWest;
                    System.out.println("arah : northWest" );
                    break;
                case 2:
                    precedence = north;
                    System.out.println("arah : north" );
                    break;
                case 3:
                    precedence = northEast;
                    System.out.println("arah : northEast" );
                    break;
                case 4:
                    precedence = west;
                    System.out.println("arah : west" );
                    break;
                case 6:
                    precedence = east;
                    System.out.println("arah : east" );
                    break;
                case 7:
                    precedence = southWest;
                    System.out.println("arah : southWest" );
                    break;
                case 8:
                    precedence = south;
                    System.out.println("arah : south" );
                    break;
                case 9:
                    precedence = southEast;
                    System.out.println("arah : southEast" );
                    break;
            }

            int[] next = new int[2];
            for (int i = 0; i < precedence.length(); i++) {
                System.out.print("arah " + precedence.charAt(i) );
                if(isAvailable(matrix, nextX, nextY, (precedence.charAt(i) - 48))) {
                    System.out.print("OK");
                    chain_code += precedence.charAt(i);
                    next = getNext(nextX, nextY, (precedence.charAt(i) - 48));

                    break;
                }
                System.out.println("");
            }
            
            nextX = next[0];
            nextY = next[1];
            iteration++;
        } 
        
        //System.out.println("Chain code = " + chain_code);
        
        return startX + "X" + startY + "Y" + chain_code;
        
    }
    
    
    private String createThinningChainCode(int[][] matrix, int startX, int startY) {
        
        String chain_code = "";
        
        String north        = "12369874";
        String northEast    = "23698741";
        String east         = "36987412";
        String southEast    = "69874123";
        String south        = "98741236";
        String southWest    = "87412369";
        String west         = "74123698";
        String northWest    = "41236987";
        
        String precedence = southEast;
        
        int direction;
        
        int nextX = -99;
        int nextY = -99;
        
        int iteration = 0;
        
        boolean isAvailable = true;
        while ((!(startX == nextX) || !(startY == nextY))) {
            if (chain_code.isEmpty()) {
                direction = 0;
                nextX = startX;
                nextY = startY;   
            } else {
                direction = chain_code.charAt(chain_code.length() - 1) - 48;
            }
            
            //System.out.println("************************************************");
            //System.out.println("Iterasi ke-" + (iteration + 1) + " = " + nextX + " " + nextY);
            
            switch(direction) {
                case 1:
                    precedence = northWest;
                    break;
                case 2:
                    precedence = north;
                    break;
                case 3:
                    precedence = northEast;
                    break;
                case 4:
                    precedence = west;
                    break;
                case 6:
                    precedence = east;
                    break;
                case 7:
                    precedence = southWest;
                    break;
                case 8:
                    precedence = south;
                    break;
                case 9:
                    precedence = southEast;
                    break;
            }

            int[] next = new int[2];
            for (int i = 0; i < precedence.length(); i++) {
                if(isThinningAvailable(matrix, nextX, nextY, (precedence.charAt(i) - 48))) {
                    chain_code += precedence.charAt(i);
                    next = getNext(nextX, nextY, (precedence.charAt(i) - 48));
                    
                    // Add Mark to the last position
                    
                    break;
                }
            }
            
            nextX = next[0];
            nextY = next[1];
            iteration++;
        } 
        
        //System.out.println("Chain code = " + chain_code);
        
        return startX + "X" + startY + "Y" + chain_code;
        
    }
    
    private boolean isThinningAvailable(int[][] matrix, int startX, int startY, int direction ) {
        
        int[] position = getNext(startX, startY, direction);
        
        int posX = position[0];
        int posY = position[1];
                
        int maxX = matrix.length - 1;
        int maxY = matrix[0].length - 1;
        
        switch(direction) {
            case 1:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == 0) {
                    return false;
                } else {
                    if ((matrix[posX + 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 2:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == 0) {
                    if (startY == 0) {
                        return false;
                    } else if (matrix[posX][posY] == 0) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY - 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 3:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == 0) {
                    return false;
                } else {
                    if ((matrix[posX][posY - 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 4:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == maxY) {
                    if (startX == 0) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX + 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 6:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == 0) {
                    if (startX == maxX) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX - 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 7:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == maxX) {
                    return false;
                } else {
                    if ((matrix[posX][posY + 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 8:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == maxX) {
                    if (startY == maxY) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY + 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 9:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == maxY) {
                    return false;
                } else {
                    if ((matrix[posX - 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
        }
        
        return false;
    }
    
    private boolean isAvailable(int[][] matrix, int startX, int startY, int direction ) {
        
        int[] position = getNext(startX, startY, direction);
        
        int posX = position[0];
        int posY = position[1];
        
        
        System.out.println((posX ) +"," + posY );
                        
        int maxX = matrix.length - 1;
        int maxY = matrix[0].length - 1;
        
        switch(direction) {
            case 1:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == 0) {
                    return false;
                } else {
                    if ((matrix[posX + 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 2:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == 0) {
                    if (startY == 0) {
                        return false;
                    } else if (matrix[posX][posY] == 0) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY - 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 3:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == 0) {
                    return false;
                } else {
                    if ((matrix[posX][posY - 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 4:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == maxY) {
                    if (startX == 0) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX + 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 6:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == 0) {
                    if (startX == maxX) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX - 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 7:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == maxX) {
                    return false;
                } else {
                    if ((matrix[posX][posY + 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 8:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startX == maxX) {
                    if (startY == maxY) {
                        return false;
                    } else if (matrix[posX][posY] == 1) {
                        return true;
                    }
                } else {
                    if ((matrix[posX][posY + 1] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
            case 9:
                //System.out.print("Nilai matrik di posisi " + direction + "(" + posX + "," + posY + ")" + " = " + matrix[posX][posY]);
                if (startY == maxY) {
                    return false;
                } else {
                    if ((matrix[posX - 1][posY] == 1) && (matrix[posX][posY] == 0)) {
                        return true;
                    }
                }
                break;
        }
        
        return false;
    }
    
    private int[] getNext(int startX, int startY, int direction) {
        int[] valueNext = new int[2];
        
        switch(direction) {
            case 1:
                valueNext[0] = startX - 1;
                valueNext[1] = startY - 1;
                        
                break;
            case 2:
                valueNext[0] = startX - 1;
                valueNext[1] = startY;
                
                break;
            case 3:
                valueNext[0] = startX - 1;
                valueNext[1] = startY + 1;
                
                break;
            case 4:
                valueNext[0] = startX;
                valueNext[1] = startY - 1;
                
                break;
            case 6:
                valueNext[0] = startX;
                valueNext[1] = startY + 1;
                
                break;
            case 7:
                valueNext[0] = startX + 1;
                valueNext[1] = startY - 1;
                
                break;
            case 8:
                valueNext[0] = startX  + 1;
                valueNext[1] = startY;
                
                break;
            case 9:
                valueNext[0] = startX + 1;
                valueNext[1] = startY + 1;
                
                break;
        }
        
        return valueNext;
        
    }
    
    private int[][] floodFill(int[][] matrix, int posX, int posY, int targetColor) {

        boolean[][] painted = new boolean[matrix.length][matrix[0].length];
        
        for (int m = 0; m < matrix.length; m++) {
            for (int n = 0; n < matrix[0].length; n++) {
                if(matrix[m][n] == targetColor) {
                    painted[m][n] = true;
                } else {
                    painted[m][n] = false;
                }
            }
        }
        
        Queue<Point> queue = new LinkedList<>();
        queue.add(new Point(posX, posY));
        painted[posX][posY] = true;
        
        
        while (!queue.isEmpty()) {
            Point pos = queue.remove();
            
            //System.out.println("NOW!!" + pos.toString());
            
            if(!(matrix[pos.x][pos.y] == targetColor)) {
                matrix[pos.x][pos.y] = targetColor;
            }
            
            if(!(matrix[pos.x+1][pos.y] == targetColor) && !(painted[pos.x+1][pos.y])) {
                painted[pos.x+1][pos.y] = true;
                queue.add(new Point(pos.x+1, pos.y));
            }
            if(!(matrix[pos.x-1][pos.y] == targetColor) && !(painted[pos.x-1][pos.y])) {
                painted[pos.x-1][pos.y] = true;
                queue.add(new Point(pos.x-1, pos.y));
            }
            if(!(matrix[pos.x][pos.y+1] == targetColor) && !(painted[pos.x][pos.y+1])) {
                painted[pos.x][pos.y+1] = true;
                queue.add(new Point(pos.x, pos.y+1));
            }
            if(!(matrix[pos.x][pos.y-1] == targetColor) && !(painted[pos.x][pos.y-1])) {
                painted[pos.x][pos.y-1] = true;
                queue.add(new Point(pos.x, pos.y-1));
            }
        }
        
        return matrix;
    }
    
    private String getChainCode(String chain_code) {
        return chain_code.substring(chain_code.indexOf("Y") + 1);
    }
    
    private int[] getFrequency(String chain_code) {
        int[] frequency = new int[9];
        
        String code = chain_code.substring(chain_code.indexOf("Y") + 1);
        
        for (int i = 0; i < code.length(); i++) {
            frequency[code.charAt(i) - 49]++;
        }
        
        return frequency;
    }
    
    private String getSequence(String chain_code) {
        String sequence = "";
        
        String code = chain_code.substring(chain_code.indexOf("Y") + 1);
        
        sequence += code.charAt(0);
        for (int i = 1; i < code.length(); i++) {
            if (sequence.charAt(sequence.length() - 1) != code.charAt(i)) {
                sequence += code.charAt(i);
            }
        }
       
        return sequence;
    }
    
    private boolean maybeSquere(String code, String sequence, int[] frequence) {
        return sequence.length() == 4;
    }
    
    private boolean maybeTriangle(String code, String sequence, int[] frequence) {
        if (sequence.length() == 3) {
            return true;
        }
        return false;
    }
    
    private boolean maybeDiamond(String code, String sequence, int[] frequence) {
        int garisMiring = cekGarisMiring(sequence);
        int garisLurus  = cekGarisLurus(code);
        
        if (garisMiring == 4 && !(maybeCircle(code, sequence, frequence)) && 
                !sequence.contains("6") && !sequence.contains("2") && !sequence.contains("8") && !sequence.contains("4") ) {
            return garisLurus == 0;
        }
        
        return false;
    }
    
    private boolean maybeCircle(String code, String sequence, int[] frequence) {
       
        float chance = new ChainCode("lingkaran",0, 0, sequence,true).compareWithBase(new ChainCode("lingkaran",0, 0, 
                "edcbahgf",true)) ;
        if ( chance > 0.4 ) {
            return true;
        }
        
        return false;
    }
    
    private boolean maybeHexagon(String code, String sequence, int[] frequence) {
        /*int garisLurus  = cekGarisLurus(code);
        int garisMiring = cekGarisMiring(sequence);
        
        return (garisLurus == 2) && (garisMiring == 4);*/
        return sequence.length() == 6;
    }
    
    private int cekGarisLurus(String code) {
        int garisLurus = 0;
        
        //System.out.println(code);
        
        if (code.contains("222222")) {
            garisLurus++;
        }
        if (code.contains("444444")) {
            garisLurus++;
        }
        if (code.contains("666666")) {
            garisLurus++;
        }
        if (code.contains("888888")) {
            garisLurus++;
        }
        
        //System.out.println(garisLurus);
        
        return garisLurus;
    }
    
    private int cekGarisMiring(String sequence) {
        int garisMiring = 0;
        
        //System.out.println(sequence.);
        
        if (sequence.contains("898989")) {
            garisMiring++;
        }
        if (sequence.contains("323232")) {
            garisMiring++;
        }
        if (sequence.contains("878787")) {
            garisMiring++;
        }
        if (sequence.contains("121212")) {
            garisMiring++;
        }
        if (sequence.contains("696969")) {
            garisMiring++;
        }
        if (sequence.contains("747474")) {
            garisMiring++;
        }
        if (sequence.contains("414141")) {
            garisMiring++;
        }
        if (sequence.contains("636363")) {
            garisMiring++;
        }
        
        System.out.println(garisMiring);
        return garisMiring;
    }
    
    
}
